import re

from django.conf import settings
from  django.core.mail import  send_mail
from rest_framework import serializers
from django_redis import get_redis_connection
from rest_framework.generics import CreateAPIView
from rest_framework_jwt.settings import api_settings

from celery_tasks.email.tasks import send_email
from users.models import User
from  itsdangerous import  TimedJSONWebSignatureSerializer as TJS

# 定义一个序列化器
class UserSerializers(serializers.ModelSerializer):
    # 显示指明模型中没有的字段,不需要序列化返回设置write_only=True
    sms_code = serializers.CharField(max_length=6, write_only=True)
    password2 = serializers.CharField(max_length=20, min_length=8, write_only=True)
    allow = serializers.CharField(write_only=True)
    # （3）.添加字段
    token = serializers.CharField(read_only=True)

    class Meta:
        model = User
        # 添加字段到模型中
        fields = ('id', 'username', 'mobile', 'email', 'sms_code', 'password2', 'allow', 'password', 'token')

    # 添加额外属性
    extra_kwargs = {
        'password': {
            'max_length': 20,
            'min_length': 8,
            'write_only': True,
            'error_messages': {
                'max_length': '密码过长'
            }
        },
        'username': {
            'max_length': 20,
            'min_length': 5,
            'error_messages': {
                'max_length': '用户名格式错误',
                'min_length': '用户名格式错误'
            }
        },

    }

    # 对手机号验证
    def validated_mobile(self, value):
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机格式不正确')
        return value

    # 验证同意协议
    def validated_allow(self, value):
        if value != 'true':
            raise serializers.ValidationError('请勾选同意')

    # 密码验证
    def validate(self, attrs):

        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError('二次密码不一致')

        # 短信验证
        # 从数据库redis中取出短信验证码
        # 1.建立链接
        conn = get_redis_connection('verify')

        # 2.获取数据（bytes类型）
        real_sms_code = conn.get('sms_%s' % attrs['mobile'])
        # 判断验证码是否过期
        if not real_sms_code:
            raise serializers.ValidationError('短信失效')

        # 3.转换数据格式为字符串
        real_sms_code = real_sms_code.decode()

        # 4.对比验证
        if attrs['sms_code'] != real_sms_code:
            raise serializers.ValidationError('短信有误')

        # 5.返回验证后的结果
        return attrs

    # 重写父类方法
    def create(self, validated_data):
        # 删除没用的数据
        del validated_data['sms_code']
        del validated_data['password2']
        del validated_data['allow']

        # user = super().create(validated_data)
        # 第一种加密方式：调用django的认证加密密码
        # user.set_password(validated_data['password'])
        # user.save()

        # 第二种加密：通过管理器方法
        user = User.objects.create_user(username=validated_data['username'],
                                        mobile=validated_data['mobile'], password=validated_data['password'])

        # （2）.手动创建新令牌，需要在返回结果之前进行生成
        # 生成载荷部分（保存用户信息）
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 对user对象添加token属性字段
        user.token = token

        return user


# 定义个人中心序列化器
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'
        # fields=('username','email','mobile','id')


class UserEmailSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email',)

    # 跟新数据email
    def update(self, instance, validated_data):
        user = self.context['request'].user

        # 加密返回的token值
        tjs=TJS(settings.SECRET_KEY,300)
        token = tjs.dumps({"username": instance.username}).decode()
        # 构建发送邮件链接
        to_email=validated_data['email']
        verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=' + token

        # 异步任务调用-发送邮件
        send_email(to_email,verify_url)

        # 保存邮件
        instance.email = validated_data['email']
        instance.save()

        return instance
